//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

namespace OpenLS.Spreadsheet.UI
{
    partial class DragDropListBoxResources
    {
        public DragDropListBoxResources()
        {
            InitializeComponent();
        }
        private void ListBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            var lb = (ListBox)sender;
            UIElement container;
            object data = GetObjectDataFromPoint(lb, e.GetPosition(lb), out container);
            if (data != null)
                DragDropElement.SetObject(lb, data);
            lb.CaptureMouse();
        }
        private static object GetObjectDataFromPoint(ListBox source, Point point, out UIElement dataContainer)
        {
            if (source == null) throw new ArgumentNullException("source");
            dataContainer = null;
            var element = source.InputHitTest(point) as UIElement;
            if (element != null)
            {
                //get the object from the element
                object data = DependencyProperty.UnsetValue;
                while (data == DependencyProperty.UnsetValue)
                {
                    // try to get the object value for the corresponding element
                    data = source.ItemContainerGenerator.ItemFromContainer(element);

                    //get the parent and we will iterate again
                    if (data == DependencyProperty.UnsetValue)
                        element = VisualTreeHelper.GetParent(element) as UIElement;

                    //if we reach the actual listbox then we must break to avoid an infinite loop
                    if (element == source)
                        return null;
                }

                //return the data that we fetched only if it is not Unset value, which would mean that we did not find the data
                if (data != DependencyProperty.UnsetValue)
                {
                    dataContainer = element;
                    return data;
                }
            }

            return null;
        }


        private void ListBox_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            var lb = (ListBox)sender;
            var obj = DragDropElement.GetObject(lb) as Sheet;
            UIElement container;
            var obj2 = GetObjectDataFromPoint(lb, e.GetPosition(lb), out container) as Sheet;
            if (obj != null)
            {
                var data = (ObservableCollection<Sheet>)lb.ItemsSource;
                int oldIndex = data.IndexOf(obj);
                int newIndex = data.IndexOf(obj2);
                if (obj2 != null && oldIndex != newIndex && oldIndex >= 0)
                    data.Move(oldIndex, newIndex);


            }
            RemoveAdorners(lb, AdornerLayer.GetAdornerLayer((Visual)lb.Parent));
            lb.ReleaseMouseCapture();
        }

        private void ListBox_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            var lb = (ListBox)sender;
            if (Mouse.Captured != lb)
                return;
            Point point = e.GetPosition(lb);
            UIElement container;
            AdornerLayer layer = AdornerLayer.GetAdornerLayer(lb.Parent as Visual);
            RemoveAdorners(lb, layer);


            GetObjectDataFromPoint(lb, point, out container);
            if (container != null)
            {
                var item = (ListBoxItem)container;
                DragDropElement.SetTarget(lb, item);
                layer.Add(new TriangleAdorner(item));
            }

        }

        private void RemoveAdorners(ListBox lb, AdornerLayer layer)
        {
            ListBoxItem i = DragDropElement.GetTarget(lb);
            if (i != null)
            {
                Adorner[] aa = layer.GetAdorners(i);
                if (aa != null)
                    foreach (Adorner a in aa)
                    {
                        layer.Remove(a);
                    }
            }
        }
        class TriangleAdorner : Adorner
        {
            public TriangleAdorner(UIElement adornedElement)
                : base(adornedElement)
            {
            }

            protected override void OnRender(DrawingContext drawingContext)
            {
                var adornedElementRect = new Rect(AdornedElement.DesiredSize);
                Brush renderBrush = Brushes.Black;
                double x = adornedElementRect.TopLeft.X;
                const double width = 8;
                const double height = 3;
                x -= width / 2;
                const double y = -height;
                var drawing = new GeometryDrawing(
                    renderBrush, null,

                    new PathGeometry(
                        new[]
                            {
                                new PathFigure
                                    (
                                    new Point(x + 0, y),
                                    new PathSegment[]
                                        {
                                            new LineSegment(
                                                new Point(x + 0, y), true),
                                            new LineSegment
                                                (new Point(x + width,
                                                           y), true),
                                            new LineSegment
                                                (new Point(x + width/2,
                                                           height/2), true),
                                            new LineSegment
                                                (new Point(x + 0, y),
                                                 true)
                                        }, true)
                            }));
                drawingContext.DrawDrawing(drawing);
            }
        }
    }
}
